home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
Database
/
SimpleTableView-1
/
FileTable.m
< prev
next >
Wrap
Text File
|
1995-06-12
|
8KB
|
321 lines
// -------------------------------------------------------------------------------------
// FileTable
// This software is without warranty of any kind. Use at your own risk.
// -------------------------------------------------------------------------------------
#import <objc/objc.h>
#import <appkit/appkit.h>
#import <mach/mach.h>
#import <dbkit/dbkit.h>
#import <libc.h>
#import <stdio.h>
#import <string.h>
#import <ctype.h>
#import "FileTable.h"
// -------------------------------------------------------------------------------------
@implementation FileTable
// -------------------------------------------------------------------------------------
/* count items in an unparsed table */
static int dt_countList(char *list)
{
int c;
char *r = list;
/* make sure there is at least one entry */
if (!r) return 0;
while (isspace(*r)) r++;
if (!*r) return 0;
/* count remaining entries */
for (c = 0, r = list; *r;) {
c++;
while (*r && !isspace(*r)) r++; // skip value
while (isspace(*r)) r++; // skip white
}
return c;
}
/* count items in a parsed table */
static int dt_countTable(char **tbl)
{
int c;
if (!tbl) return 0; // no entries counted
for (c = 0; tbl[c]; c++);
return c;
}
/* parse a string table */
static char **dt_parseTable(char *list)
{
int n, tblSize;
char **theTbl, *r;
/* skip whitespace in list */
if (!list) return (char**)NULL;
while (isspace(*list)) list++;
if (!*list) return (char**)NULL;
/* count items in table */
tblSize = sizeof(char*) * (dt_countList(list) + 1); // include terminator
theTbl = (char**)malloc(tblSize);
memset(theTbl, 0, tblSize);
/* fill table */
for (n = 0, r = list; *r;) {
theTbl[n++] = r;
while (*r && !isspace(*r)) r++;
while (isspace(*r)) *r++ = 0;
}
/* return the table */
return theTbl;
}
// -------------------------------------------------------------------------------------
/* return access timestamp */
- (time_t)timestamp
{
struct stat st;
if (stat((char*)tableHandle->access, &st) < 0) {
NXLogError("Unable to stat file %s", tableHandle->access);
return 0;
}
return st.st_mtime;
}
// -------------------------------------------------------------------------------------
- _addSimpleColumn:(char*)title :(char)cType :(float)size
{
int t;
char *types = CDT_TYPES;
dataColumn_t *dc = (dataColumn_t*)malloc(sizeof(dataColumn_t));
memset(dc, 0, sizeof(dataColumn_t));
for (t = 0; types[t] && (types[t] != cType); t++);
dc->index = [tableHandle->columnId count];
dc->type = types[t]? t : CDT_UNKNOWN;
dc->keyTag = NXCopyStringBuffer(title);
dc->title = (char*)nil;
dc->size = size;
dc->minSize = 0.0;
dc->displayOrder = dc->index;
dc->alignment = NX_CENTERED;
dc->isEditable = dc->index? YES : NO;
dc->isHidden = (dc->displayOrder >= 0)? NO : YES;
dc->nilValue = (char*)nil;
[self addColumnInfo:dc];
return self;
}
/* load table column info */
- readTableColumns
{
char buf[2048];
BOOL cLoaded = NO, vLoaded = NO;
FILE *fh;
/* open table */
if (!(fh = fopen(tableHandle->access, "r"))) {
NXLogError("Unable to open file %s", tableHandle->access);
return (id)nil;
}
/* find/read column information */
while (fgets(buf, sizeof(buf), fh) && (*buf == '#')) {
/* view information */
if (!vLoaded && !strncmp(buf, "#!t", 3)) {
char viewName[128];
NXSize s = { 0.0, 0.0 };
sscanf(buf + 4, "%s %f %f", viewName, &s.width, &s.height);
tableHandle->viewSize = s;
vLoaded = YES;
continue;
}
/* column information */
if (!cLoaded && (!strncmp(buf, "#!c\t", 4) || !strncmp(buf, "#\t", 2))) {
int key, numCols;
char **tbl, *b = buf + 1;
for (;*b && (*b != ' ') && (*b != '\t'); b++);
for (;(*b == ' ') || (*b == '\t'); b++);
if (!(tbl = dt_parseTable(b))) continue;
numCols = dt_countTable(tbl);
for (key = 0; key < numCols; key++) {
float size = 0.0;
char *title = tbl[key], *p = index(title, ':'), ctype[4];
if (p) { *p++ = 0; sscanf(p, "%c:%f", ctype, &size); }
[self _addSimpleColumn:title :*ctype :size];
}
free(tbl);
cLoaded = YES;
continue;
}
}
/* close table */
fclose(fh);
return self;
}
// -------------------------------------------------------------------------------------
/* load table */
- readTableData
{
FILE *fh;
u_int r;
char buf[4096];
int count = [tableHandle->columnId count];
/* open table */
if (!tableHandle->access) return (id)nil;
if (!(fh = fopen((char*)tableHandle->access, "r"))) {
NXLogError("Unable to open file %s", tableHandle->access);
return (id)nil;
}
/* read table data */
for (r = 0; fgets(buf, sizeof(buf), fh);) {
int c, tlen;
id rowId;
char **tbl;
if (!*buf || (*buf == '#') || (*buf == '\t') || (*buf == ' ')) continue;
if (!(tbl = dt_parseTable(buf))) continue;
rowId = [[List alloc] initCount:count];
[tableHandle->dataId insertObject:rowId at:r];
for (tlen = dt_countTable(tbl), c = 0; c < count; c++) {
char *val = (c < tlen)? tbl[c] : (char*)nil;
dataEntry_t *de = entryNEW;
de->value = (char*)[self copyStringValue:val forColumn:c];
de->isValid = -1;
[rowId insertObject:(id)de at:c];
}
free(tbl);
r++;
}
/* close table */
fclose(fh);
return self;
}
// -------------------------------------------------------------------------------------
- writeTable
{
int r, c;
FILE *fh;
struct stat st;
/* make backup copy */
if (stat(tableHandle->access, &st) >= 0) {
char bku[MAXPATHLEN + 1];
sprintf(bku, "%s~", tableHandle->access);
if (rename(tableHandle->access, bku)) {
NXLogError("Unable to rename file %s to %s", tableHandle->access, bku);
return (id)nil;
}
}
/* open file for writing */
if (!(fh = fopen(tableHandle->access, "w+"))) {
NXLogError("Unable to open file %s", tableHandle->access);
return (id)nil;
}
/* view header */
fprintf(fh, "#!t %s %.0f %.0f\n", tableHandle->name,
tableHandle->viewSize.width, tableHandle->viewSize.height);
/* column headers */
fprintf(fh, "#!c\t");
for (c = 0; c < [tableHandle->columnId count]; c++) {
dataColumn_t *ci = [self columnInfoAt:c];
fprintf(fh, "%s:%c:%.0f\t", ci->keyTag, *(CDT_TYPES + ci->type), ci->size);
}
fprintf(fh, "\n");
/* data */
for (r = 0; r < [tableHandle->dataId count]; r++) {
id rowId = [tableHandle->dataId objectAt:r];
for (c = 0; c < [rowId count]; c++) {
dataColumn_t *ci = [self columnInfoAt:c];
dataEntry_t *de = entryPTR(rowId, c);
if (c) fprintf(fh, "\t");
fprintf(fh, "%s", (*de->value?de->value:(ci->nilValue?ci->nilValue:"*")));
}
fprintf(fh, "\n");
}
/* close file */
fclose(fh);
/* re-stat file to get modified date */
if (stat((char*)tableHandle->access, &st) >= 0) tableHandle->date = st.st_mtime;
else NXLogError("Unable to stat file %s", tableHandle->access);
return self;
}
// -------------------------------------------------------------------------------------
/* create value for column */
- (const char*)copyStringValue:(const char*)value forColumn:(int)index
{
char *vcopy, buff[64];
dataColumn_t *dc = [self columnInfoAt:index];
/* check arguments */
if (!dc) return (char*)nil;
/* special return types */
switch (dc->type) {
case CDT_BOOLEAN:
return NXCopyStringBuffer(((value && strcmp(value,"NO"))?"YES":"NO"));
break;
case CDT_INTEGER:
sprintf(buff, "%d", (value?atoi(value):0));
return NXCopyStringBuffer(buff);
break;
case CDT_STRING:
default:
if (!value) return NXCopyStringBuffer("");
for (vcopy = (char*)value; isspace(*vcopy); vcopy++); // skip white space
vcopy = strcpy((char*)malloc(strlen(vcopy) + 1), vcopy);
{ char *b,*v; for (b=v=vcopy;*v;v++) if(!isspace(*v)){if(b!=v)*b=*v;b++;} *b=0; }
if (dc->nilValue && !strcmp(dc->nilValue, vcopy)) *vcopy = 0;
return (char*)realloc(vcopy, strlen(vcopy) + 1);
break;
}
/* control should not reach here */
return NXCopyStringBuffer("");
}
// -------------------------------------------------------------------------------------
/* validate specific value (intended for subclass implementation) */
- (BOOL)verifyValue:(const char*)value dataType:(int)dataType
{
if (!value) return NO;
switch (dataType) {
case CDT_STRING:
case CDT_INTEGER:
default:
return YES;
}
return YES;
}
// -------------------------------------------------------------------------------------
@end